<?php

require_once dirname(__FILE__).'/Crumbs/Node.php';

class Zend_View_Helper_Crumbs implements Countable, IteratorAggregate
{
	static private $_mvc = false;
	private $_firstAndLastNode = true;
	private $_crumbs = null;
	private $_iterator = null;
	private $_request = null;
	private $_view = null;
	private $area = null;
	private $_disallowModule = array('index');
	private $_disallowController = array('index');
	private $_disallowAction = array('index');
	private $_prepend = null;
	private $_append = null;
	private $_module = null;
	private $_controller = null;
	private $_action = null;
	private $_context = null;
	private $_baseUrl = null;
	private $_separator = '»';
	private $_generateModule = true;
	private $_generateController = true;
	private $_generateAction = true;
	const DIR_SEPARATOR = '/';

        public function crumbs($prepend = array(), $append = array(), $separator = '')
	{
		$this->_initCrumbs();
		$this->_prepend = $prepend;
		$this->_append = $append;
		$this->_separator = $separator;
		$this->_baseUrl = $this->getRequest()->getBaseUrl();
		return $this;
	}
	public function init()
	{
		$this->_buildPrepend();
		if(true === self::$_mvc){
			$this->_buildCrumbs();
		}
		$this->_buildAppend();
		return $this;
	}
	private function _initCrumbs()
	{
		if(null === $this->_crumbs){
			$this->_crumbs = new ArrayObject();
		}
		if (!$this->_crumbs instanceof ArrayObject) {
			throw new Zend_Controller_Exception('Zend_View_Helper_Crumbs: Invalid ArrayObject class');
		}
		return $this;
	}
	public function getRequest()
	{
		if(null === $this->_request){
			$this->_request = Zend_Controller_Front::getInstance()->getRequest();
		}
		if (!$this->_request instanceof Zend_Controller_Request_Abstract) {
			throw new Zend_Controller_Exception('Zend_View_Helper_Crumbs: Invalid request class');
		}
		return $this->_request;
	}
	public function setRequest(Zend_Controller_Request_Abstract $request)
	{
		$this->_request = $request;
	}
	public function setView(Zend_View_Abstract $view)
	{
		$this->_view = $view;
		return $this;
	}
	public function setMvc($mvc = false)
	{
		self::$_mvc = (boolean) $mvc;
		return $this;
	}
	public function setFirstAndLastNode($firstAndLastNode)
	{
		$this->_firstAndLastNode = (boolean) $firstAndLastNode;
		return $this;
	}
	public function setArea($area)
	{
		$this->area = $area;
		return $this;
	}
	public function getArea()
	{
		return $this->area;
	}
	public function setSeparator($separator)
	{
		$this->_separator = $separator;
		return $this;
	}
	public function getSeparator()
	{
		return $this->_separator;
	}
	public function getModuleName()
	{
		return $this->_module;
	}
	public function getControllerName()
	{
		return $this->_controller;
	}
	public function getActionName()
	{
		return $this->_action;
	}
	public function getGenerateModule()
	{
		return $this->_generateModule;
	}
	public function setGenerateModule($generateModule)
	{
		$this->_generateModule = $generateModule;
		return $this;
	}
	public function getGenerateController()
	{
		return $this->_generateController;
	}
	public function setGenerateController($generateController)
	{
		$this->_generateController = $generateController;
		return $this;
	}
	public function getGenerateAction()
	{
		return $this->_generateAction;
	}
	public function setGenerateAction($generateAction)
	{
		$this->_generateAction = $generateAction;
		return $this;
	}
	private function getDictionary($text)
	{
		$elementArr = explode(' ', $text);
		foreach ($elementArr as $element){
			$elementArrResult[] = ucwords($element);
		}
		return implode(' ', $elementArrResult);
	}
	public function delete($node)
	{
		if($this->_crumbs->offsetExists($node)){
			$this->_crumbs->offsetUnset($node);
		}
		return $this;
	}
	private function _addCrumb($crumbName, Zend_View_Helper_Crumbs_Node $node, $validate = true)
	{
		if(true === $validate){
			if (true === isset($crumbName) && false === $this->_crumbs->offsetExists($crumbName) ){
				$this->_crumbs->offsetSet($crumbName, $node);
			}
		} elseif(true === isset($crumbName)){
			$this->_crumbs->offsetSet($crumbName, $node);
		} else {
			throw new Exception('Error Exception: Crumb Name is Empty');
		}
		return $this;
	}
	public function add(Zend_View_Helper_Crumbs_Node $node)
	{
		$this->_addCrumb($node->getId(), $node);
		return $this;
	}
	public function addCrumb($crumbName, $label, $title, $link, $first = false, $last = false)
	{
		if(empty($crumbName) || empty($label)){
			throw new Exception('Error Exception: Crumb Name or Label is Empty, must be a string');
		}
		$node = new Zend_View_Helper_Crumbs_Node();
		$node->setId($crumbName)
		->setLabel($label)
		->setTitle($title)
		->setLink($link);
		$this->_addCrumb($node->getId(), $node);
	}
	public function addPrepend($url, $name)
	{
		$this->_prepend[$url] = $name;
		return $this;
	}
	public function addAppend($url, $name)
	{
		$this->_append[$url] = $name;
		return $this;
	}
	private function _buildCrumbs()
	{
		$this->_module = $this->getRequest()->getModuleName();
		$this->_controller = $this->getRequest()->getControllerName();
		$this->_action = $this->getRequest()->getActionName();
		if(null !== $this->getArea()){
			$this->_context = self::DIR_SEPARATOR . $this->getArea() . self::DIR_SEPARATOR;
		}
		if(true === $this->getGenerateModule()){
			$this->_buildModule();
		}
		if(true === $this->getGenerateController()){
			$this->_buildController();
		}
		if(true === $this->getGenerateAction()){
			$this->_buildAction();
		}
	}
	private function _buildPrepend()
	{
		if($this->_prepend !== null)
		{
			foreach($this->_prepend as $url => $name)
			{
				$this->addCrumb($name, $name, $name, $this->_baseUrl . $url);
			}
		}
	}
	private function _buildAppend()
	{
		if($this->_append !== null)
		{
			foreach($this->_append as $url => $name)
			{
				$this->addCrumb($name, $name, $name, $this->_baseUrl . $url);
			}
		}
	}
	private function _buildModule()
	{
		if($this->_module !== null && !in_array($this->_module, $this->_disallowModule))
		{
			$name = $this->_module;
			$url = $this->_baseUrl . self::DIR_SEPARATOR . $this->_module .  self::DIR_SEPARATOR;
                        
			$this->addCrumb($name . '-module', $this->getDictionary($name), $name, $url);
		}
	}
	private function _buildController()
	{
		if($this->_controller !== null && !in_array($this->_controller, $this->_disallowController))
		{
			$name = $this->_formatController($this->_controller);
			$url =  $this->_baseUrl . self::DIR_SEPARATOR . $this->_module . self::DIR_SEPARATOR . $this->_controller . self::DIR_SEPARATOR;
			$this->addCrumb($this->_controller . '-controller', $this->getDictionary($name), $name, $url);
		}
	}
	private function _buildAction()
	{
		if($this->_action !== null && !in_array($this->_action, $this->_disallowAction))
		{
			$name = $this->_formatAction($this->_action);
			$url =  $this->_baseUrl . self::DIR_SEPARATOR . $this->_module . self::DIR_SEPARATOR . $this->_controller . self::DIR_SEPARATOR . $this->_action . self::DIR_SEPARATOR;
			$this->addCrumb($this->_action . '-action', $this->getDictionary($name), $name, $url);
		}
	}
	private function _firstAndLastNode(ArrayIterator $iterator)
	{
		$this->getNode($iterator->key())->setFirst(true);
		$this->getNode($this->count()-1)->setLast(true);
	}
	public function getNode($index)
	{
		if(isset($index) && is_numeric($index)){
			$iterator = $this->getIterator();
			$iterator->seek($index);
			$node = $iterator->current();
		} elseif (isset($index) && $this->_crumbs->offsetExists($index)){
			$node =  $this->_crumbs->offsetGet($index);
		}
		if($node instanceof Zend_View_Helper_Crumbs_Node){
			return $node;
		}
		throw new Exception('Node: ' . $index . ' Not Exist in the Crumb Collection');
	}
	protected function _formatController($theString)
	{
		return preg_replace('/default-/', '', $theString);
	}
	protected function _formatAction($theString)
	{
		return str_replace('_'," ", $theString);
	}
	public function toString()
	{
		if ($this->count()> 0) {
			$iterator = $this->getIterator();
			if(true === $this->_firstAndLastNode){
				$this->_firstAndLastNode($iterator);
			}
			$this->_view->crumbs = $this->getIterator();
			$this->_view->separator = $this->_separator;
			return $this->_view->render('breadcrumbs.phtml');
		}
		return null;
	}
	public function count()
	{
		return $this->_crumbs->count();
	}
	public function getIterator()
	{
		if($this->_iterator instanceof ArrayIterator){
			$this->_iterator->rewind();
		} else {
			$this->_iterator = $this->_crumbs->getIterator();
		}
		return $this->_iterator;
	}
	public function __toString()
	{
		try {
			return $this->toString();
		} catch (Exception $e) {
			trigger_error($e->getMessage(), E_USER_WARNING);
		}
		return '';
	}
}